﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    //TODO: Bernsen, Test
    /// <summary>
    ///For each pixel (x, y), the threshold T (x, y) = (Zlow + Zhigh)/2 is used, 
    ///where Zlow and Zhigh are the lowest and
    ///highest gray level pixel values in a square r × r neighborhood
    ///centered at (x, y). 
    ///If the contrast measure 
    ///C(x, y) = Zhigh − Zlow is smaller than l, then the neighborhood consists of only
    ///one class, that is assumed to be a background. Trier and Taxt
    ///recommend r = 15 and l = 15.
    /// </summary>
    public class Bernsen : BaseForeBackgroundColorFilter
    {
        protected int m_nSize = 15;
        protected int m_nContrastMeasure = 15;
        protected bool m_bUseContrastMeasure = false;

        /// <summary>
        /// Default constructor
        /// </summary>
        public Bernsen()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Bernsen"/> class.
        /// </summary>
        /// <param name="_bernsen">The _bernsen.</param>
        internal Bernsen(Bernsen _bernsen)
        {
            this.m_nSize = _bernsen.m_nSize;
            this.m_nContrastMeasure = _bernsen.m_nContrastMeasure;
            this.m_bUseContrastMeasure = _bernsen.m_bUseContrastMeasure;
        }

        /// <summary>
        /// Gets or sets the size.
        /// </summary>
        /// <value>The size.</value>
        public int Size
        {
            get { return m_nSize; }
            set { m_nSize = value; }
        }

        /// <summary>
        /// Gets or sets the contrast measure.
        /// </summary>
        /// <value>The contrast measure.</value>
        public int ContrastMeasure
        {
            get { return m_nContrastMeasure; }
            set { m_nContrastMeasure = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether [use contrast measure].
        /// </summary>
        /// <value><c>true</c> if [use contrast measure]; otherwise, <c>false</c>.</value>
        public bool UseContrastMeasure
        {
            get { return m_bUseContrastMeasure; }
            set { m_bUseContrastMeasure = value; }
        }

        /// <summary>
        /// Execute this filter
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap bitmapCloned = (UnsafeBitmap)_bitmap.Clone();
            int nHeight = _bitmap.Height;
            int nWidth = _bitmap.Width;
            int y = 0;
            int x = 0;

            int nHalfWindowSize = m_nSize / 2;

            int nSize = 0;

            int[] a = new int[m_nSize * m_nSize];

            int nIndex = 0;
            int nMinValue = 5000;
            int nMaxValue = 0;
            int nThreshold = 0;

            int nZLow = 50000;
            int nZHigh = 0;
            int nX = 0;
            int nY = 0;
            int nValueOriginal = 0;
            int nValue = 0;
            for (y = m_nSize; y < nHeight - m_nSize; y++)
            {
                for (x = m_nSize; x < nWidth - m_nSize; x++)
                {
                    nIndex = 0;
                    nValueOriginal = bitmapCloned[nX, nY, true].R;
                    for (nSize = 0; nSize < m_nSize; nSize++)
                    {
                        nX = x + nSize - nHalfWindowSize;
                        nY = y + nSize - nHalfWindowSize;
                        nValue = bitmapCloned[nX, nY, true].R;
                        if (nValue < nZLow) nZLow = nValue;
                        if (nValue > nZHigh) nZHigh = nValue;
                    }
                    nThreshold = (nZLow + nZHigh) / 2;
                    int nNewValue = nValueOriginal - nThreshold;

                    if (m_bUseContrastMeasure)
                    {
                        _bitmap.SetPixel(x, y, nNewValue < m_nContrastMeasure ? m_ColorBackground : m_ColorForeground);
                    }
                    else
                    {
                        _bitmap.SetPixel(x, y, nNewValue > 0 ? m_ColorForeground : m_ColorBackground);
                    }
                }
            }
            return _bitmap;
        }

        ///// <summary>
        ///// Execute this filter
        ///// </summary>
        ///// <param name="_bitmap"></param>
        ///// <returns></returns>
        //public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        //{
        //    UnsafeBitmap bitmapCloned = (UnsafeBitmap)_bitmap.Clone();
        //    int nHeight = _bitmap.Height;
        //    int nWidth = _bitmap.Width;
        //    int y = 0;
        //    int x = 0;

        //    int nHalfWindowSize = m_nSize / 2;

        //    int nSize = 0;

        //    int[] a = new int[m_nSize * m_nSize];

        //    int nIndex = 0;

        //    int nMinValue = 5000;
        //    int nMaxValue = 0;
        //    int nThreshold = 0;
        //    int nZLow = 0;
        //    int nZHigh = 0;

        //    for (y = m_nSize; y < nHeight - m_nSize; y++)
        //    {
        //        for (x = m_nSize; x < nWidth - m_nSize; x++)
        //        {
        //            nIndex = 0;
        //            for (nSize = 0; nSize < m_nSize; nSize++)
        //            {
        //                for (nSize = 0; nSize < m_nSize; nSize++)
        //                {
        //                    int nX = x - nHalfWindowSize;
        //                    int nY = y - nHalfWindowSize;
        //                    a[nIndex] = bitmapCloned[nX, nY, true].R;
        //                    nIndex++;
        //                }
        //            }
        //            Array.Sort(a);
        //            nZLow = a[0];
        //            nZHigh = a[a.Length - 1];
        //            nThreshold = (nZLow + nZHigh) / 2;
        //            _bitmap.SetPixel(x, y, 
        //                (nZHigh - nZLow) < m_nContrastMeasure ? Definitions.Black : 
        //                    nThreshold > m_nContrastMeasure ? Definitions.White : Definitions.Black);
        //            Array.Clear(a, 0, a.Length);
        //        }
        //    }
        //    return _bitmap;
        //}

        /// <summary>
        /// Clones this filter
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new Bernsen(this);
        }
    }
}
